/*
 * Alloy Analyzer
 * Copyright (c) 2002 Massachusetts Institute of Technology
 *
 * The Alloy Analyzer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The Alloy Analyzer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Alloy Analyzer; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package alloy.sharbool;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.xml.transform.Templates;

import alloy.ast.Node;
import alloy.util.ObjID;

/**
 * Represents a template to which one or more {@link alloy.ast.Node}s conform.
 * <p>
 * Note that this object represents only the identity of the template, not its
 * structure -- i.e. there is no copy of the template with formal arguments
 * to be replaced by actual arguments.
 */
class Template extends ObjID {
      ////////////
     // Fields //
    ////////////
    
    /**
     * Parent templates: {@link Set} of {@link Templates} which have this template as their child.
     * Each {@link TemplateInstance#node} of each parent template has a {@link Node#getChildren child}
     * matching <code>this</code> {@link Template}.
     * <p>
     * We use {@link #templateParents} in
     * {@link TemplateDetectVisitor#visit(Node)} to narrow the list of
     * candidate templates that a {@link Node} might match, when
     * determining for a node which (if any) of previously seen
     * templates it matches.  We do this after we've determined the
     * template representative for each of the node's children.  If
     * this node matches a previously-seen template, that template
     * must be a template parent of the template of each child; this
     * narrows down the list of candidate templates considerably.
     */
    Set /* of Template */ parents = new TreeSet();

    /**
     * Children templates: for each {@link TemplateInstance instance} of this {@link Template},
     * the i'th child of {@link TemplateInstance#node} matches the template referenced by
     * the i'th element of {@link #children}.
     */
    Template[] children;

    /**
     * Template instances: information about {@link Node}s which are instances of this template.  {@link List} of
     * {@link TemplateInstance}s.  It must be a {@link List}, and not a {@link Set},
     * to guarantee that {@link #getAnInstance} always returns the same representative instance.
     */
    List /* of TemplateInstance */ instances = new ArrayList();

    /**
     * For each argument position, information on the range of possible values
     * of the argument in that position: whether it is always a singleton bit,
     * or can be blank, or can have multiple "1" bits.
     */
    List argMults;

      /////////////
     // Methods //
    /////////////

    /**
     * Return a representative {@link TemplateInstance instance} of this {@link Template} --
     * always returns the same instance.
     */
    TemplateInstance getAnInstance() { return (TemplateInstance)instances.get(0); }

    /**
     * Returns the size of the {@link TemplateInstance#args} list of each
     * {@link #instances instance} of this template -- the size must be
     * the same for all instances of this template.
     */
    int getNumArgs() { return getAnInstance().args.size(); }

    /**
     * Shorten the argument list of  every {@link #instances instance}, to include
     * only those arguments whose numbers are given in the {@link List} of {@link Integer}s
     * passed to this routine.  Used by {@link TemplateDetectVisitor#_shortenTemplateArgLists}.
     */
    void keepOnlyArgs(List /* of Integer */ argsToKeep_) {
	if (argsToKeep_.size() < getNumArgs()) {
	    for (Iterator instIter = instances.iterator();
		 instIter.hasNext();) {
		TemplateInstance templInst = (TemplateInstance)instIter.next();
		List newArgList = new ArrayList();
		for (Iterator keepIter = argsToKeep_.iterator(); keepIter.hasNext();) {
		    Integer keepArgIdx = (Integer)keepIter.next();
		    newArgList.add(templInst.args.get(keepArgIdx.intValue()));
		}
		templInst.setArgs(newArgList);
	    }  // drop the args from each instance
	}  // if we've found args we can drop
    }
}
